#File:scu.py
"""
Author: Albert Rondan
This is the schedule control/creation unit; A console application that let's a user
create a schedule using desired input (single and double round robin),
save it, output it, etc.
"""
import re, string
import cgi
import cgitb

#self created Module
import Module
loaded = [] #this contains whatever schedule we are working with
currentInput = ""
currentFileName = ""
offset = 0

def main():
    print "Welcome to Tenniscores Schedule Creation Unit [Created by Albert Rondan] \n"
    print "NOTE: Currently this programmed is designed to just retrieve the best fit schedule that is generated. Just one, so you won't see all the others with fitness near it."
    print "Please input one of the numbered options from the menu below to begin"
    print "1.) Create a new single round robin tennis schedule"
    print "2.) Create a new double round robin tennis schedule"
    print "3.) Load a previously created schedule"
    print "4.) Output current schedule to screen or text file"
    print "5.) Quit! \n"
    option = int(raw_input("Enter a number and press enter to continue :: "))

    if option == 1:
        single(0)
    elif option == 2:
        double()
    elif option == 3:
        load(0)
    elif option == 4:
        output()
    elif option == 5:
        return
    else:
        print "That is not a valid option, try again"
        raw_input("That is not a valid option, press any key to try again")
        main()
def display(command): 
    totalOut=""
    #r = open('output','w')
    for line in command.stdout.readlines():
        #print line,
    #	r.write(line)
        totalOut+=line+"\n"
    retval = command.wait()
    return totalOut
	#r.close()
def single( op ):
    global loaded
    loaded = []
    print "Please place the input file in the same directory as this file, then input the name of the file. Example :: input.txt"
    name = str(raw_input("File name :: "))
    
    global currentFileName
    currentFileName = name
    #Take input file, concatenate logic program to it, run it using subprocess, store output and use it when calling Module.main()
    stream = open(name,'r')
    output = stream.read()
    stream.close()

    #Store the input
    global currentInput
    currentInput = output
    output +="N { res(B,I,A,W) : div(X,A) : div(X,B) : divweek(X,W) : inst(B,I,_,_) }N :- division(X), divsize(X,N). \n"
    output +=":- res(A,I,A,W). \n"
    output +=":- res(A,_,B,_), res(B,_,A,_). \n"
    output +=":- res(A,_,B,W), res(A,_,B,W1), W<W1. \n" 
    output +=":- res(A,I,B,_), res(A,I1,B,_), I<I1. \n"		
    output +=":- res(A,I,B,W), res(A,I1,B1,W), B<B1, inst(A,I,T,D), inst(A,I1,T,D). \n"						
    output +=":- res(B,I,A,W), res(B1,I1,A,W), B<B1, inst(B,I,T,D), inst(B1,I1,T,D). \n"					
    output +=":- res(A,I,B,W), res(B1,I1,A,W), inst(A,I,T,D), inst(B1,I1,T,D). \n"
    output +=":- res(A,I,B,W), home(A,C), nonweek(C,W). \n"
    output +=":- res(A,I,B,W), inst(A,I,T,D), home(A,C), nonday(C,W,D). \n"
    output +=":- res(A,I,B,W), inst(A,I,T,D), home(A,C), nontime(C,W,D,T). \n"
    #output +="connected(1) :- res(A,I,B,1). \n"
    #output +="connected(X) :- connected(X-1), res(A,I,B,X). \n"
    #output +=":- not connected(X), X=w. \n"
    #output +="gameson(W,N) :- res(A,I,B,W), N = #count{ res(_,_,_,W) }. \n"
    #Be careful here, this is where you establish your bounds. If you are having a hard time finding a schedule in a reasonable time, change these up and relax the bounds.
    #output +=":- gameson(W,N), N < (d-1). \n"
    #output +=":- gameson(W,N), N > (t/w)+1. \n"         #so this might make solutions hard to find, needs testing
    output +="#hide. \n"
    output +="#show res/4."
    #print output
    
    import subprocess

    print "Generating schedules..."
    p = subprocess.Popen("echo \""+output+"\" | clingo 100",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    #p = subprocess.Popen("clingo tenniscores",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    results = display(p).split("\n")
    #print results    
    #if results.find("UN"):
    #    print "UNSATISFIABLE"
    final=Module.main(results, name).split(" ")
    for match in final:
        global loaded
        loaded.append(match)
    #print loaded
    #should i autosave it into a temp file? Naahhh
    #remember, after creating the schedule, you should load it into loaded
    raw_input("Single round robin schedule created. Press any key to continue.")
    if op == 0:
        main()
    elif op == 1:
        return
def double():
    
    single(1)
    # A single round robin schedule has been created. Now just concatenate loaded's contents onto an empty string, copy inputs over, and copy double round robin logic as well. run it. done.
    output = ""
    loaded = loaded[0:len(loaded)-1]
    for result in loaded:
        output+= result.replace("res","prev") + ".\n"
        output+= "\n"
    
    print "Please place the second input file in the same directory as this file, then enter the name of the file. Example :: input2.txt"
    name = str(raw_input("File name :: "))
    global currentFileName
    currentFileName = name
    #Take input file, concatenate logic program to it, run it using subprocess, store output and use it when calling Module.main()
    stream = open(name,'r')
    output += stream.read()
    stream.close()
    #Find #const w=X and store X
    
    placeHolder = output[output.find("#const w = "):]       #changes nothing functionally, still working on it.
    global offset
    offset = placeHolder[0:placeHolder.find(".")]
    print offset

    # Ok so here I actually want to ask for the input of the second input file, which just 
    # contains just the last bit (NOTE: do i need the const for weeks and do I need to do anything with the max() facts?
    # otherwise the only thing different is the nondates() and the divweek() seperations
    #output+= currentInput
    print "\n\n\n\nDropping the week constraint allows matches to be inverted, but the weeks of the matches can be different. This gives more schedules to work with when trying to make sure the 'nonDates' work well. \n"
    option = int(raw_input("If you would like to drop the same week constraint enter 1, otherwise enter 0 :: "))
    #Give option to keep week constraint or to drop it.

    if option == 0 :
        output+= "N { res(B,I,A,W) : prev(A,_,B,W) : div(X,B) : div(X,A) : inst(B,I,_,_) }N :- division(X), divsize(X,N). \n"
        output+= ":- res(A,I,A,W). \n"
        output+= ":- res(A,_,B,_), res(B,_,A,_). \n"
        output+= ":- res(A,_,B,W), res(A,_,B,W1), W<W1. \n"
        output+= ":- res(A,I,B,_), res(A,I1,B,_), I<I1. \n"
        output+= ":- res(A,I,B,W), res(A,I1,B1,W), B<B1, inst(A,I,T,D), inst(A,I1,T,D). \n"					
        output+= ":- res(B,I,A,W), res(B1,I1,A,W), B<B1, inst(B,I,T,D), inst(B1,I1,T,D). \n"						
        output+= ":- res(A,I,B,W), res(B1,I1,A,W), inst(A,I,T,D), inst(B1,I1,T,D). \n"
        output+= "%:- res(A,I,B,W), home(A,C), nonweek(C,W). \n"
        output+= "%:- res(A,I,B,W), inst(A,I,T,D), home(A,C), nonday(C,W,D). \n"
        output+= "%:- res(A,I,B,W), inst(A,I,T,D), home(A,C), nonday(C,W,D,T).  \n"
        output +="connected(1) :- res(A,I,B,1). \n"
        output +="connected(X) :- connected(X-1), res(A,I,B,X). \n"
        output +=":- not connected(X), X=w. \n"
        output +="gameson(W,N) :- res(A,I,B,W), N = #count{ res(_,_,_,W) }. \n"
        output +=":- gameson(W,N), N < (d-1). \n"
        output +=":- gameson(W,N), N > (t/w)+1. \n"
    elif option == 1 :
        output+= "N { res(B,I,A,W) : prev(A,_,B,_) : div(X,B) : div(X,A) : divweek(X,W) : inst(B,I,_,_) } N :- division(X), divsize(X,N). \n"
        output+= ":- res(A,I,A,W). \n"
        output+= ":- res(A,_,B,_), res(B,_,A,_). \n"
        output+= ":- res(A,_,B,W), res(A,_,B,W1), W<W1. \n"
        output+= ":- res(A,I,B,_), res(A,I1,B,_), I<I1. \n"
        output+= ":- res(A,I,B,W), res(A,I1,B1,W), B<B1, inst(A,I,T,D), inst(A,I1,T,D). \n"					
        output+= ":- res(B,I,A,W), res(B1,I1,A,W), B<B1, inst(B,I,T,D), inst(B1,I1,T,D). \n"						
        output+= ":- res(A,I,B,W), res(B1,I1,A,W), inst(A,I,T,D), inst(B1,I1,T,D). \n"
        output+= ":- res(A,I,B,W), home(A,C), nonweek(C,W). \n"
        output+= ":- res(A,I,B,W), inst(A,I,T,D), home(A,C), nonday(C,W,D). \n"
        output+= ":- res(A,I,B,W), inst(A,I,T,D), home(A,C), nonday(C,W,D,T).  \n"
        output +="connected(1) :- res(A,I,B,1). \n"
        output +="connected(X) :- connected(X-1), res(A,I,B,X). \n"
        output +=":- not connected(X), X=w. \n"
        output +="gameson(W,N) :- res(A,I,B,W), N = #count{ res(_,_,_,W) }. \n"
        output +=":- gameson(W,N), N < (d-1). \n"
        output +=":- gameson(W,N), N > (t/w)+1. \n"
    output+= "#hide. \n"
    output+= "#show res/4. \n"
    
    
    import subprocess
    #subprocess.Popen("echo \""+output+"\" >> output.txt",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    print "Generating schedules..."
    #ATTENTION! THIS IS THE LINE YOU CHANGE TO GENERATE MORE SCHEDULES (DEFAULT:100) THE HIGHER YOU GO, THE MORE OPTIMAL, but be careful, around 1mil is a good point but will take a while
    p = subprocess.Popen("echo \""+output+"\" | clingo 100",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    #p = subprocess.Popen("clingo tenniscores",shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    results = display(p).split("\n")
    #display(p)
    
    atlast=Module.main(results, currentFileName).split(" ")
    #print currentFileName
    #global loaded
    #loaded.append("SECOND ROUND ROBIN BEGINS HERE")
    for match in atlast:
        #print match
        global loaded
        loaded.append(match)
    
    #should i autosave it into a temp file? Naahhh
    #remember, after creating the schedule, you should load it into loaded
    raw_input("Double round robin schedule created. Press any key to continue to the main menu")

    main()
    #the order will be (first schedule, then the second one, line by line)
def load( op ): 
    global loaded
    loaded = []
    if op == 0: #user selected
        print "Please input the name of the file containing the schedule."
        name = str(raw_input("File name :: "))
        print "Loading schedule from " + name + "..."
        # we assuming a format where each match pairing is on its own line
        opened = open(name,'r')
        for match in opened:
            loaded.append(str(match).rstrip())

        opened.close()
    else:
        print "Loading..."

   
    main()
    
def output():

    print "Enter 0 to output to the screen, 1 to output to a text file, and 2 to output to a spreadsheet (Pyexcelerator needs to be installed)"
    option = int(raw_input("Enter option [0|1|2] :: "))
    print "Outputting schedule..."
    if option == 0 :
        for result in loaded:
            print(result)
       
    elif option == 1 :
        print "Please enter the name of the file you whish to create. Example :: output.txt"
        name = str(raw_input("Enter name :: "))
        f = open(name,'w')
        print "Writing to file " + name + "..."
        for result in loaded:
            f.write(result)
            f.write("\n")
        f.close()
    elif option == 2 :
        output = ""
        for result in loaded:
            output+= result + " "
        import visual
        visual.main(output)
        print "Schedule has been saved to visual.xls in the current directory. ENJOY!"

    print "Done"
    raw_input("Press any key to continue to the main menu")
    main()
    

main()
